package org.hawk.gwt.ppc.scanner.utils;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import org.hawk.gwt.ppc.reflect.lang.SystemClassLoader;

/**
 * Represents all the definitions stored in the single block of code.
 * @author alex.bereznevatiy@gmail.com
 */
public class JavaScope {
	private JavaScope parent;
	private List<JavaScope> children;
	private int start;
	private int end;
	protected List<JavaVariable> vars;

	JavaScope(JavaScope parent,int start,List<JavaVariable> vars) {
		this.parent = parent;
		this.children = new LinkedList<JavaScope>();
		this.vars = Collections.unmodifiableList(vars);
		this.start = start;
	}
	
	void addChild(JavaScope child){
		if(child==null){
			throw new NullPointerException("Child is NULL");
		}
		children.add(child);
	}
	
	void endScope(int end){
		this.children = Collections.unmodifiableList(children);
		this.end = end;
	}
	/**
	 * @param index
	 * @return list of java variables for specific iterator index.
	 */
	public List<JavaVariable> getVariables(int index) {
		List<JavaVariable> result = new LinkedList<JavaVariable>();
		if(getParent()!=null){
			result.addAll(getParent().getVariables(index));
		}
		for(JavaVariable var : vars){
			if(var.isDeclaredAt(index)){
				result.add(var);
			}
		}
		return Collections.unmodifiableList(result);
	}
	/**
	 * @param index
	 * @param name
	 * @return variable with name specified that is declared at
	 * specific point or <code>null</code> if there is no such variable.
	 */
	public JavaVariable getVariable(int index, String name) {
		ListIterator<JavaVariable> iterator = vars.listIterator(vars.size());
		while(iterator.hasPrevious()){
			JavaVariable var = iterator.previous();
			if(var.isDeclaredAt(index)&&
				var.getName().equals(name)){
				return var;
			}
		}
		if(getParent()!=null){
			return getParent().getVariable(index,name);
		}
		return null;
	}
	/**
	 * @return parent scope (or <code>null</code> if it is top-level scope)
	 */
	public JavaScope getParent() {
		return parent;
	}
	/**
	 * @param index
	 * @return child scope for iterator index specified 
	 */
	public JavaScope getScope(int index) {
		for(JavaScope child : children){
			JavaScope rez = child.getScope(index);
			if(rez!=null)return rez;
		}
		if(index>=start&&index<end){
			return this;
		}
		return null;
	}
	/**
	 * @return list of children scopes
	 */
	public List<JavaScope> getChildren() {
		return children;
	}

	protected String resolveType(String typeSimpleName){
		if(SystemClassLoader.isPrimitiveClass(typeSimpleName)){
			return typeSimpleName;
		}
		if(getParent()==null){
			return typeSimpleName;
		}
		return getParent().resolveType(typeSimpleName);
	}
}